package kuzha.code.jvm;

import static kuzha.code.jvm.CodeGenUtils.emitNumber;
import static org.objectweb.asm.Opcodes.ACONST_NULL;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.PUTSTATIC;
import kuzha.KuzhaObject;
import kuzha.runtime.Converter;
import kuzha.runtime.KzBigNumber;
import kuzha.runtime.KzBoolean;
import kuzha.runtime.KzNull;
import kuzha.runtime.KzNumber;
import kuzha.runtime.KzRegex;
import kuzha.runtime.KzString;

import org.objectweb.asm.MethodVisitor;

class ConstantPool extends AbstractPool<KuzhaObject> {
	public ConstantPool(String fieldsPrefix, String systemName) {
		super(fieldsPrefix, systemName, "Lkuzha/KuzhaObject;");
	}
	
	protected void emitInitializeConstant(MethodVisitor mv, String fieldname, KuzhaObject obj) {
		if (obj instanceof KzNumber) {
			// KzNumber.valueOf(value)
			emitNumber(mv, Converter.cast(Number.class, obj));
			mv.visitMethodInsn(INVOKESTATIC, "kuzha/runtime/KzNumber", "valueOf", "(Ljava/lang/Number;)Lkuzha/runtime/KzNumber;");
		}
		else if (obj instanceof KzBigNumber) {
			// KzBigNumber.valueOf(value)
			emitNumber(mv, Converter.cast(Number.class, obj));
			mv.visitMethodInsn(INVOKESTATIC, "kuzha/runtime/KzBigNumber", "valueOf", "(Ljava/lang/Number;)Lkuzha/runtime/KzBigNumber;");
		}
		else if (obj instanceof KzString) {
			// KzString.valueOf(value);
			mv.visitLdcInsn(((KzString)obj).value);
			mv.visitMethodInsn(INVOKESTATIC, "kuzha/runtime/KzString", "valueOf", "(Ljava/lang/String;)Lkuzha/runtime/KzString;");
		}
		else if (obj instanceof KzRegex) {
			// KzRegex.valueOf(value);
			mv.visitLdcInsn(((KzRegex)obj).value.pattern());
			mv.visitMethodInsn(INVOKESTATIC, "kuzha/runtime/KzRegex", "valueOf", "(Ljava/lang/String;)Lkuzha/runtime/KzRegex;");
		}
		else {
			throw new IllegalArgumentException("unknown objs: " + obj);
		}
		mv.visitFieldInsn(PUTSTATIC, systemName, fieldname, "Lkuzha/KuzhaObject;");
	}
	
	public void emitLoadConstants(MethodVisitor mv, KuzhaObject obj) {
		if (obj == null) {
			// null
			mv.visitInsn(ACONST_NULL);
		}
		else if (obj instanceof KzNull) {
			// KzNull.NULL
			mv.visitFieldInsn(GETSTATIC, "kuzha/runtime/KzNull", "NULL", "Lkuzha/runtime/KzNull;");
		}
		else if (obj instanceof KzBoolean) {
			if (((KzBoolean)obj).value)
				mv.visitFieldInsn(GETSTATIC, "kuzha/runtime/KzBoolean", "TRUE", "Lkuzha/runtime/KzBoolean;");
			else
				mv.visitFieldInsn(GETSTATIC, "kuzha/runtime/KzBoolean", "FALSE", "Lkuzha/runtime/KzBoolean;");
		}
		else {
			super.emitLoadConstants(mv, obj);
		}
	}
}
